package com.lib.utils;

import android.content.ContentResolver;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.database.Cursor;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.net.Uri;
import android.os.Handler;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;

import java.util.ArrayList;

public class ScreenShotManager {
    /**
     * 读取媒体数据库时需要读取的列, 其中 WIDTH 和 HEIGHT 字段在 API 16 以后才有
     */
    private final String[] mMediaProjectionsApi16 = {
            MediaStore.Images.ImageColumns.DATA,
            MediaStore.Images.ImageColumns.DATE_TAKEN,
            MediaStore.Images.ImageColumns.WIDTH,
            MediaStore.Images.ImageColumns.HEIGHT,
    };

    /**
     * 截屏依据中的路径判断关键字
     */
    private final String[] mKeywords = {
            "screen", "screenshot", "screen_shot", "screen-shot", "screen shot",
            "screencapture", "screen_capture", "screen-capture", "screen capture",
            "screencap", "screen_cap", "screen-cap", "screen cap", "截屏"
    };
    private final String KEY_PORTRAIT_SIZE = "portrait_size";
    private final String KEY_LANDSCAPE_SIZE = "landscape_size";

    /**
     * 已回调过的路径
     */
    private ArrayList<String> sHasCallbackPaths = new ArrayList<>();

    private Resources mResources;

    private long mStartListenTime;

    private int mPortraitHeight;
    private int mPortraitWidth;

    private int mLandscapeWidth;
    private int mLandscapeHeight;

    private ContentResolver mResolver;
    private OnScreenShotListener mListener;
    /**
     * 内部存储器内容观察者
     */
    private MediaContentObserver mInternalObserver;
    /**
     * 外部存储器内容观察者
     */
    private MediaContentObserver mExternalObserver;

    private ScreenShotManager() {
        mResources = XLog.sContext.getResources();
        mResolver = XLog.sContext.getContentResolver();
    }

    private static class InnerClass {
        private static ScreenShotManager sScreenShotManager = new ScreenShotManager();
    }

    public static ScreenShotManager getInstance() {
        return InnerClass.sScreenShotManager;
    }

    /**
     * 启动监听
     *
     * @param handler 处理器
     */
    public void startListener(Handler handler) {
//        sHasCallbackPaths.clear();
        /*记录开始监听的时间戳*/
        mStartListenTime = System.currentTimeMillis();
        XLog.i("mStartListenTime->" + mStartListenTime);

        if (mInternalObserver == null) {
            /* 注册内部存储的内容观察者 */

            mInternalObserver = new MediaContentObserver(handler, MediaStore.Images.Media.INTERNAL_CONTENT_URI);
            mResolver.registerContentObserver(MediaStore.Images.Media.INTERNAL_CONTENT_URI, false, mInternalObserver);
            /* 创建外部存储的内容观察者 */
            mExternalObserver = new MediaContentObserver(handler, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
            mResolver.registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, false, mExternalObserver);
        }
    }

    /**
     * 停止监听
     */
    public void onDestroy() {
        if (XLog.sContext == null) {
            return;
        }
        XLog.i("stopListener ->");
        // 注销内容观察者

        if (mInternalObserver != null) {
            try {
                mResolver.unregisterContentObserver(mInternalObserver);
            } catch (Exception ignored) {
            }
            mInternalObserver = null;
        }
        if (mExternalObserver != null) {
            try {
                mResolver.unregisterContentObserver(mExternalObserver);
            } catch (Exception ignored) {
            }
            mExternalObserver = null;
        }

        // 清空数据
        sHasCallbackPaths.clear();
    }

    public boolean setLandscapeSize(String size) {
        String[] str = size.split(",");
        try {
            mLandscapeWidth = Integer.parseInt(str[0]);
            mLandscapeHeight = Integer.parseInt(str[1]);
            SPUtils.getSP().edit().putString(KEY_LANDSCAPE_SIZE, size).apply();
            return true;
        } catch (Exception ignored) {
            mLandscapeWidth = 0;
            mLandscapeHeight = 0;
        }
        return false;
    }

    public boolean setPortraitSize(String size) {
        String[] str = size.split(",");
        try {
            mPortraitWidth = Integer.parseInt(str[0]);
            mPortraitHeight = Integer.parseInt(str[1]);
            SPUtils.getSP().edit().putString(KEY_PORTRAIT_SIZE, size).apply();
            return true;
        } catch (Throwable ignored) {
            mPortraitWidth = 0;
            mPortraitHeight = 0;
        }
        return false;
    }

    /**
     * 处理媒体数据库的内容改变
     */
    private void handleMediaContentChange(Uri contentUri) {
        XLog.i(String.valueOf(System.currentTimeMillis()));
        Cursor cursor = null;
        try {
            // 数据改变时查询数据库中最后加入的一条数据
            String sortOrder = MediaStore.Images.ImageColumns.DATE_ADDED + " desc limit 1";
            cursor = XLog.sContext.getContentResolver().query(contentUri, mMediaProjectionsApi16, null, null, sortOrder);

            if (cursor == null) {
                XLog.w("cursor is null.");
                return;
            }
            if (!cursor.moveToFirst()) {
                XLog.w("Cursor no data.");
                return;
            }

            // 获取各列的索引
            int dataIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
            int dateTakenIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATE_TAKEN);

            int widthIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.WIDTH);
            int heightIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.HEIGHT);

            // 获取行数据
            String path = cursor.getString(dataIndex);
            long dateTaken = cursor.getLong(dateTakenIndex);
            int width = 0;
            int height = 0;
            if (widthIndex >= 0 && heightIndex >= 0) {
                width = cursor.getInt(widthIndex);
                height = cursor.getInt(heightIndex);
            } else {
                // API 16 之前, 宽高要手动获取
                Point size = getImageSize(path);
                width = size.x;
                height = size.y;
            }
            // 处理获取到的第一行数据
            handleMediaRowData(path, dateTaken, width, height);
        } catch (Exception e) {
            if (mListener != null) {
                mListener.onScreenShot(0, 0, e.getMessage());
            }
            XLog.i("e->" + Log.getStackTraceString(e));
        } finally {
            if (cursor != null && !cursor.isClosed()) {
                cursor.close();
            }
        }
    }

    private Point getImageSize(String imagePath) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(imagePath, options);
        return new Point(options.outWidth, options.outHeight);
    }

    /**
     * 处理获取到的一行数据
     */
    private void handleMediaRowData(String path, long dateTaken, int width, int height) {
        if (checkScreenShot(path, dateTaken, width, height)) {
            XLog.i("ScreenShot: path = " + path + "; size = " + width + " * " + height + "; date = " + dateTaken);
            if (mListener == null) {
                XLog.i("mListener == null");
                return;
            }
            if (!checkPathIsValid(path)) {
                if (mListener != null && checkPathIsValid(path)) {
                    mListener.onScreenShot(0, 0, "checkPathIsValid false");
                }
                return;
            }
            mListener.onScreenShot(width, height, path);
        } else {
            // 如果在观察区间媒体数据库有数据改变，又不符合截屏规则，则输出到 log 待分析
            String msg = "待分析: path = " + path + "; size = " + width + " * " + height + "; date = " + dateTaken;
            XLog.w(msg);
            if (mListener != null && checkPathIsValid(path)) {
                mListener.onScreenShot(0, 0, msg);
            }
        }
    }

    /**
     * 判断指定的数据行是否符合截屏条件
     */
    private boolean checkScreenShot(String path, long dateTaken, int width, int height) {
        if (TextUtils.isEmpty(path)) {
            return false;
        }
        /*
         * 判断依据一: 时间判断
         */
        // 如果加入数据库的时间在开始监听之前, 或者与当前时间相差大于10秒, 则认为当前没有截屏
        if (dateTaken < mStartListenTime || (System.currentTimeMillis() - dateTaken) > 10 * 1000) {
            return false;
        }
        /*
         * 判断依据二: 尺寸判断
         */
        Configuration configuration = mResources.getConfiguration();
        DisplayMetrics dm = mResources.getDisplayMetrics();
        if (configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            if (mLandscapeWidth == 0) {
                String str = SPUtils.getSP().getString(KEY_LANDSCAPE_SIZE, "0,0");
                setLandscapeSize(str);
            }
            if (mLandscapeWidth == width && height == mLandscapeHeight) {
                return true;
            }
            // 如果横屏，图高必须等于屏幕高
            if (height != dm.heightPixels) {
                return false;
            }
            // 如果图宽小于屏幕高，则不是截屏
            if (width <= dm.heightPixels) {
                return false;
            }
        } else if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
            if (mPortraitWidth == 0) {
                String str = SPUtils.getSP().getString(KEY_PORTRAIT_SIZE, "0,0");
                setPortraitSize(str);
            }
            if (mPortraitWidth == width && height == mPortraitHeight) {
                return true;
            }
            // 如果竖屏，图宽必须等于屏幕宽
            if (width != dm.widthPixels) {
                return false;
            }
            // 如果图高小于屏幕宽，则不是截屏
            if (height <= dm.widthPixels) {
                return false;
            }
        }
        /*
         * 判断依据三: 路径判断
         */
        path = path.toLowerCase();
        // 判断图片路径是否含有指定的关键字之一, 如果有, 则认为当前截屏了
        for (String keyWork : mKeywords) {
            if (path.contains(keyWork)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断是否已回调过, 某些手机ROM截屏一次会发出多次内容改变的通知; <br/>
     * 删除一个图片也会发通知, 同时防止删除图片时误将上一张符合截屏规则的图片当做是当前截屏.
     */
    private boolean checkPathIsValid(String imagePath) {
        if (sHasCallbackPaths.contains(imagePath)) {
            XLog.i("ScreenShot: imgPath has done; imagePath = " + imagePath);
            return false;
        }
        // 大概缓存15~20条记录便可
        if (sHasCallbackPaths.size() > 20) {
            sHasCallbackPaths.remove(0);
        }
        sHasCallbackPaths.add(imagePath);
        return true;
    }

    /**
     * 设置截屏监听器
     */
    public void setOnScreenShotListener(OnScreenShotListener listener) {
        mListener = listener;
    }

    public interface OnScreenShotListener {
        void onScreenShot(int width, int height, String imagePath);
    }

    /**
     * 媒体内容观察者(观察媒体数据库的改变)
     */
    private static class MediaContentObserver extends ContentObserver {
        private Uri mContentUri;

        public MediaContentObserver(Handler handler, Uri contentUri) {
            super(handler);
            mContentUri = contentUri;
        }

        @Override
        public void onChange(boolean selfChange) {
            getInstance().handleMediaContentChange(mContentUri);
        }
    }
}